<template>
  <div>
    <input type="file" @change="handleFileChange" />    
    <button @click="handleUpload">upload</button>
  </div>
</template>
​
<script>
// 切片大小
// the chunk size
const SIZE = 10 * 1024;
export default {
  data: () => ({
    container: {
      file: null,
    },
    data: [],
  }),
  methods: {
    handleFileChange(e) {
      const [file] = e.target.files;
      console.log(this.$data, this.$options.data());
      if (!file) return;
      this.container.file = file;
    },

    //文件切片
    createFileChunk(file, size = SIZE) {
      const fileChunkList = [];
      let cur = 0;
      while (cur < file.size) {
        fileChunkList.push({ file: file.slice(cur, cur + size) });
        cur += size;
      }
      return fileChunkList;
    },

    //点击上传
    async handleUpload() {
      if (!this.container.file) return;
      const fileChunkList = this.createFileChunk(this.container.file);
      console.log(fileChunkList);
      this.data = fileChunkList.map(({ file }, index) => ({
        chunk: file,
        // 文件名 + 数组下标
        hash: this.container.file.name + '-' + index,
      }));
      await this.uploadChunks();
    },

    // 上传切片
    async uploadChunks() {
      const requestList = this.data
        .map(({ chunk, hash }) => {
          const formData = new FormData();
          formData.append('chunk', chunk);
          formData.append('hash', hash);
          formData.append('filename', this.container.file.name);
          return { formData };
        })
        .map(({ formData }) =>
          this.request({
            url: 'http://localhost:3000',
            data: formData,
          })
        );
      // 并发请求
      await Promise.all(requestList);
      await this.mergeRequest();
    },

    //合并切片
    async mergeRequest() {
      await this.request({
        url: 'http://localhost:3000/merge',
        headers: {
          'content-type': 'application/json',
        },
        data: JSON.stringify({
          filename: this.container.file.name,
          size: SIZE,
        }),
      });
    },

    request({ url, method = 'post', data, headers = {}, requestList }) {
      return new Promise((resolve) => {
        const xhr = new XMLHttpRequest();
        xhr.open(method, url);
        Object.keys(headers).forEach((key) =>
          xhr.setRequestHeader(key, headers[key])
        );
        xhr.send(data);
        xhr.onload = (e) => {
          resolve({
            data: e.target.response,
          });
        };
      });
    },
  },
};
</script>
